package ${domain}.frame.utils;

import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import ${domain}.frame.auth.LocalData;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class SqlUtil {

    public static void exec(String sql) {
        SqlSession sqlSession = null;
        try {
            SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
            sqlSession = factory.openSession(true);
            Connection connection = sqlSession.getConnection();
            PreparedStatement statement = connection.prepareStatement(sql);
            statement.execute();
        } catch (SQLException e) {
            throw new RuntimeException(String.format("[ %s ]执行错误！", sql));
        } finally {
            if (sqlSession != null) sqlSession.close();
        }
    }

    public static int insert(String sql) {
        return update(sql);
    }

    public static int delete(String sql) {
        return update(sql);
    }

    public static int update(String sql) {
        SqlSession sqlSession = null;
        int result = 0;
        try {
            SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
            sqlSession = factory.openSession(true);
            Connection connection = sqlSession.getConnection();
            PreparedStatement statement = connection.prepareStatement(sql);
            result = statement.executeUpdate();
            statement.close();
            connection.close();
        } catch (SQLException e) {
            throw new RuntimeException(String.format("[ %s ]执行错误！", sql));
        } finally {
            if (sqlSession != null) sqlSession.close();
        }
        return result;
    }

    public static <T> List<T> select(String sql, Class<T> t) {
        List<T> result = new ArrayList<>();
        try {
            SqlSessionFactory factory = LocalData.getBean(SqlSessionFactory.class);
            SqlSession sqlSession = factory.openSession(true);
            Connection connection = sqlSession.getConnection();
            PreparedStatement statement = connection.prepareStatement(sql);
            ResultSet resultSet = statement.executeQuery();
            while (resultSet.next()) {
                T instance = t.newInstance();
                Field[] fields = t.getDeclaredFields();
                for (Field field : fields) {
                    Method method = ClassUtil.setMethod(field.getName(), t, field.getType());
                    if (field.getType() == String.class) {
                        String v = resultSet.getString(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Boolean.class || field.getType() == boolean.class) {
                        boolean v = resultSet.getBoolean(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Byte.class || field.getType() == byte.class) {
                        byte v = resultSet.getByte(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Short.class || field.getType() == short.class) {
                        short v = resultSet.getShort(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Character.class || field.getType() == char.class) {
                        short v = resultSet.getShort(field.getName());
                        method.invoke(instance, (char) v);
                    } else if (field.getType() == Integer.class || field.getType() == int.class) {
                        int v = resultSet.getInt(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Long.class || field.getType() == long.class) {
                        long v = resultSet.getLong(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Float.class || field.getType() == float.class) {
                        float v = resultSet.getFloat(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Double.class || field.getType() == double.class) {
                        double v = resultSet.getDouble(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Byte[].class || field.getType() == byte[].class) {
                        byte[] v = resultSet.getBytes(field.getName());
                        method.invoke(instance, v);
                    } else if (field.getType() == Date.class) {
                        Date v = resultSet.getDate(field.getName());
                        method.invoke(instance, v);
                    } else {
                        String v = resultSet.getString(field.getName());
                        method.invoke(instance, v);
                    }
                }
                result.add(instance);
            }
            statement.close();
            connection.close();
        } catch (SQLException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return result;
    }

}
